package com.suray.wcs.service.plc.util.impl;

import com.suray.basic.wcs.path.core.Lifter;
import com.suray.basic.wcs.path.core.Node;
import com.suray.basic.wcs.path.enums.NodeStatus;
import com.suray.basic.wcs.plc.core.Plc;
import com.suray.basic.wcs.plc.enums.LifterMode;
import com.suray.basic.wcs.plc.enums.Location;
import com.suray.basic.wcs.plc.pojo.DeviceBase;
import com.suray.basic.wcs.plc.pojo.lifter.data.map.CarMap;
import com.suray.basic.wcs.plc.pojo.lifter.data.map.LifterMap;
import com.suray.basic.wcs.plc.pojo.lifter.data.map.PalletMap;
import com.suray.basic.wcs.plc.pojo.oper.StationOper;
import com.suray.basic.wcs.plc.pojo.oper.lifter.LifterOper;
import com.suray.basic.wcs.plc.pojo.oper.lifter.ForkLifterOper;
import com.suray.basic.wcs.plc.utils.*;
import com.suray.basic.wcs.utils.Coord;
import com.suray.basic.wcs.utils.LoggerUtil;
import com.suray.commin.core.utils.SpringContextHolder;
import com.suray.wcs.service.enums.DetailProcess;
import com.suray.wcs.service.enums.PrecessOperation;
import com.suray.wcs.service.enums.PrecessStatus;
import com.suray.wcs.service.enums.TaskType;
import com.suray.wcs.service.execption.PlcExecuteException;
import com.suray.wcs.service.init.LifterInfoFunc;
import com.suray.wcs.service.init.PlcInit;
import com.suray.wcs.service.plc.LifterEvent;
import com.suray.wcs.service.plc.LifterLocationInfo;
import com.suray.wcs.service.plc.LifterTaskManage;
import com.suray.wcs.service.plc.LifterTaskThread;
import com.suray.wcs.service.pojo.Rgv;
import com.suray.wcs.service.system.entity.TaskDB;
import com.suray.wcs.service.system.entity.TaskDetailDB;
import com.suray.wcs.service.util.WcsUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.io.IOException;

@Component
public class ForkLifterEvent extends LifterEvent {

    private static Logger log = LoggerFactory.getLogger(LifterEvent.class);
    private static LifterInfoFunc lifterInfoFunc = SpringContextHolder.getBean(LifterInfoFunc.class);

    /**
     * 车请求提升机第一步
     *
     * @param endLayer 目的层
     */
    @Override
    public void rgvNotLoadAssignHoist1(LifterOper hoistOper, Lifter lifter, Rgv rgv, Integer plcId, int endLayer)
            throws PlcExecuteException, IOException {
        log.info("执行提升机车换层逻辑第一步,提升机内有货?: " + hoistOper.isPalletExisted(endLayer, Location.INSIDE) + "小车托盘升降状态" + rgv.getPalletStatus());
        //托盘状态下降状态时才可在提升机内有货的状态下调用
        if (hoistOper.isPalletExisted(endLayer, Location.INSIDE) && !rgv.isHasCargo()) {
            log.info("执行提升机车换层逻辑第一步,提升机内有货?: " + hoistOper.isPalletExisted(endLayer, Location.INSIDE) + "小车托盘升降状态" + rgv.getPalletStatus());
            validateAndCall(hoistOper, lifter, rgv, plcId, LifterMode.DEBUG, 0, Location.INSIDE, endLayer,
                    Location.INSIDE);
        } else {
            validateAndCall(hoistOper, lifter, rgv, plcId, LifterMode.UNLOADED, 0, Location.INSIDE, endLayer,
                    Location.INSIDE);
        }
        validateHoistArrived(hoistOper, endLayer, plcId, rgv);
        hoistOper.lockHoist(rgv.getRgvDB().getRgvNo());
        log.info(hoistOper.getDeviceName() + "上锁成功");
    }

    @Override
    public Integer validateAndCall(LifterOper hoistOper, Lifter lifter, Object obj, int taskNo, LifterMode lifterMode, int objFloor1, Location objLocation1, int objFloor2, Location objLocation2) throws IOException {
        // 最大值为99
        Integer code = validateParams(hoistOper, lifterMode, objFloor1, objFloor2, objLocation1, objLocation2, obj);
        ForkLifterOper forkLifterOper = (ForkLifterOper) hoistOper;
        if (obj instanceof TaskDB) {
            callLift(forkLifterOper, code, taskNo);
            LifterTaskThread.freshTaskProcess(forkLifterOper, taskNo, LifterTaskProcess.INIT);
        } else {
            callLift(forkLifterOper, code, taskNo);
        }
        forkLifterOper.setPermitClearTask(false);
        new LifterTaskThread(hoistOper.getSeries(), taskNo, forkLifterOper,
                objFloor1, objLocation1, objFloor2, objLocation2).start();
        LifterEvent.liftWord.put(hoistOper.getLockLocation().toString(), code);
        log.info("调用提升机任务字：" + code + "任务编号" + taskNo);
        return code;
    }

    /**
     * 任务是否完成
     * @param forkLifterOper
     * @param taskId
     * @return
     */
    public boolean isTaskEnd(ForkLifterOper forkLifterOper, int taskId) {
        return LifterTaskManage.getInstance(forkLifterOper).isTaskEnd(taskId);
    }

    /**
     * 指令是否完成
     * @param forkLifterOper
     * @param taskId
     * @param cmdNo
     * @return
     */
    public boolean isTaskCmdEnd(ForkLifterOper forkLifterOper, int taskId, int cmdNo) {
        return LifterTaskManage.getInstance(forkLifterOper).isTaskCmdEnd(taskId, cmdNo);
    }

    /**
     * 发送段任务
     * @param forkLifterOper
     * @param taskId
     * @return
     * @throws IOException
     */
    public LifterCurSegmentInfo sendSegment(ForkLifterOper forkLifterOper, int taskId) throws IOException {
        return LifterTaskManage.getInstance(forkLifterOper).sendSegment(taskId);
    }

    /**
     * 小车上方是否有货
     * @return
     */
    public boolean hasCargo(ForkLifterOper forkLifterOper) {
        //托盘光电有货，并且1或3方向光电有一个有货
        return forkLifterOper.isDir2PalletSig() && (forkLifterOper.isDir1PalletSig() || forkLifterOper.isDir3PalletSig());
    }

    /**
     * 写任务字以及任务号
     *
     * @param code
     * @param taskNo
     */
    public void callLift(ForkLifterOper lifterOper, int code, int taskNo) throws IOException {
        int mode = code / 1000000;
        int startFloor = code / 10000 % 100;
        int startLocation = code / 1000 % 10;
        int endFloor = code / 10 % 100;
        int endLocation = code % 10;

        LifterMode lifterMode = LifterMode.parseMode(mode);
        LifterLocationType startLocal = analyzeLocation(startLocation);
        LifterLocationType endLocal = analyzeLocation(endLocation);

        switch (lifterMode) {
            case LOAD_RGV:
            case UNLOADED:
                changeLayer(lifterOper, taskNo, endFloor);
                break;
            case LOAD_PALLET:
                transCargo(lifterOper, taskNo, startFloor, startLocal, endFloor, endLocal, null);
                lifterOper.setCode(code);
                break;
            case DEBUG:
            default:
                throw new RuntimeException("提升机任务模式错误:" + lifterMode);
        }
    }

    /**
     * 提升机任务恢复
     * @param lifterOper
     * @param code
     * @param taskNo
     * @param process
     * @throws IOException
     */
    public void callLift(ForkLifterOper lifterOper, int code, int taskNo, LifterTaskProcess process) throws IOException {
        int mode = code / 1000000;
        int startFloor = code / 10000 % 100;
        int startLocation = code / 1000 % 10;
        int endFloor = code / 10 % 100;
        int endLocation = code % 10;

        LifterMode lifterMode = LifterMode.parseMode(mode);
        LifterLocationType startLocal = analyzeLocation(startLocation);
        LifterLocationType endLocal = analyzeLocation(endLocation);

        switch (lifterMode) {
            case LOAD_RGV:
            case UNLOADED:
                changeLayer(lifterOper, taskNo, endFloor);
                break;
            case LOAD_PALLET:
                transCargo(lifterOper, taskNo, startFloor, startLocal, endFloor, endLocal, process);
                break;
            case DEBUG:
            default:
                throw new RuntimeException("提升机任务模式错误:" + lifterMode);
        }
    }

    public boolean isLocationHasCargo(LifterOper lifterOper, int floor, Location location) {
        Coord endNode = new Coord(Plc.lifterLocationMap.get(lifterOper.getPlcId()).get(location));
        endNode.setZ(floor);
        return WcsUtil.isNodeHasCargo(endNode, nodedbServiceImpl);
    }

    /**
     * 货调提升机，使用前，加锁
     *
     * @param lifterOper    提升机操作对象
     * @param lifterNode    提升机所在坐标，不是左右坐标
     * @param taskdb        当前执行的任务
     * @param startLayer    起始层
     * @param endLayer      目的层
     * @param startLocation 起始位置
     * @param endLocation   目的位置
     */
    public void palletTask(LifterOper lifterOper, Lifter lifterNode, TaskDB taskdb, Node startNode, int startLayer, int endLayer,
                           Location startLocation, Location endLocation, TaskDetailDB taskDetailDB) throws PlcExecuteException, IOException {
        log.info("任务编号" + taskdb.getTaskId() + ":货物调用提升机逻辑开始");
        log.info(lifterOper.getDeviceName() + "提升机目的位置有货?: " + lifterOper.isPalletExisted(endLayer, endLocation)
                + "提升机就绪?: " + lifterOper.isReady() + "提升机有任务?: " + (lifterOper.getHoistCurrentTaskNo() != 0)
                + "提升机内有车?: " + lifterOper.isHaveShuttle());
        boolean endHasCargo = isLocationHasCargo(lifterOper, endLayer, endLocation);
        while (endHasCargo || !lifterOper.isReady() || (lifterOper.getHoistCurrentTaskNo() != 0)
                || lifterOper.isHaveShuttle()) {
            log.info(lifterOper.getDeviceName() + "提升机目的位置有货?: " + endHasCargo
                    + "提升机就绪?: " + lifterOper.isReady() + "提升机有任务?: " + (lifterOper.getHoistCurrentTaskNo() != 0)
                    + "提升机内有车?: " + lifterOper.isHaveShuttle());
            Plc.checkPLCInterrupt(taskdb.getTaskId().toString(), "LifterEvent1");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            endHasCargo = isLocationHasCargo(lifterOper, endLayer, endLocation);
        }
        log.info("锁定提升机");
        TaskDetailDB taskDetail = taskDetailService.getTaskDetail(taskdb.getTaskId(), DetailProcess.HOIST_RUN,
                taskDetailDB.getUuid(), taskDetailDB.getStart(), taskDetailDB.getEnding(),
                PrecessStatus.CONDUCT, null, null);
        int taskNo = taskdb.getPlcId();
        Integer code = validateAndCall(lifterOper, lifterNode, taskdb, taskNo, LifterMode.LOAD_PALLET, startLayer, startLocation,
                endLayer, endLocation);
        taskDetail.setRemark(code.toString());
        taskDetailService.updateById(taskDetail);
        log.info("货调提升机结束，等待任务结束");
        endHasCargo = isLocationHasCargo(lifterOper, endLayer, endLocation);
        while (lifterOper.getHoistCurrentLayer() == 0 || lifterOper.getHoistCurrentLayer() != endLayer
                || !lifterOper.isArrived() || !endHasCargo || lifterOper.getHoistFinalTaskNo() != taskNo) {
            Plc.checkPLCInterrupt(taskdb.getTaskId().toString(), "LifterEvent2");
            if (lifterOper.getTaskProcess() != null && lifterOper.getTaskId() != null) {
                endHasCargo = isLocationHasCargo(lifterOper, endLayer, endLocation);
                if (lifterOper.getTaskProcess() == LifterTaskProcess.BACK_LIFTER && taskNo == lifterOper.getTaskId()
                        && endHasCargo) {
                    ((ForkLifterOper) lifterOper).setPermitClearTask(true);
                    LoggerUtil.info(lifterOper.getSeries() + " 当前任务：" + lifterOper.getTaskId() + ",任务进度："
                            + lifterOper.getTaskProcess() + ",终点位置有货：", LifterEvent.class);
                    break;
                }
            }

            lifterOper.setTaskDes("等待任务完成：" + taskNo);
            errorValidate(lifterOper);
            try {
                Thread.sleep(600);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        checkHoistTaskFinish(lifterOper, taskNo, endLayer, taskdb);
        log.info(lifterOper.getDeviceName() + "提升机终点位置有货,托盘调用提升机结束,任务号:" + taskNo);
        TaskDetailDB clearDet = taskDetailService.getTaskDetail(taskdb.getTaskId(), DetailProcess.CLEAR_HOIST_TASK, taskDetail.getUuid(), taskDetail.getStart(), taskDetail.getEnding(),
                PrecessStatus.CONDUCT, null, null);
        LifterEvent.liftWord.remove(lifterOper.getLockLocation().toString());
        taskDetailService.updateTaskDetailCompleteTime(clearDet);
        taskDetailService.updateTaskDetailCompleteTime(taskDetail);
    }

    /**
     * 提升机换层
     * @param lifterOper
     * @param taskNo
     * @param endFloor
     * @throws IOException
     */
    public void changeLayer(ForkLifterOper lifterOper, int taskNo, int endFloor) throws IOException {
        LifterTaskManage taskManage = LifterTaskManage.getInstance(lifterOper);
        taskManage.initLastLocation();
        taskManage.changeLifterLayerNoCmd(taskNo, endFloor,
                LifterLayerType.FOUR_CAR_LAYER);
        taskManage.sendSegment(taskNo);
    }

    /**
     * 托盘出入
     * @param lifterOper
     * @param taskNo
     * @param startFloor
     * @param startLocal
     * @param endFloor
     * @param endLocal
     * @param process
     * @throws IOException
     */
    private void transCargo(ForkLifterOper lifterOper, int taskNo, int startFloor, LifterLocationType startLocal,
                            int endFloor, LifterLocationType endLocal, LifterTaskProcess process) throws IOException {
        checkPallet(lifterOper, process, startFloor, startLocal, endFloor, endLocal);
        LifterTaskManage taskManage = LifterTaskManage.getInstance(lifterOper);
        taskManage.initLastLocation();
        //前往起点
        if (process == null || process == LifterTaskProcess.INIT || process == LifterTaskProcess.GO_TO_START) {
            gotoTarget(lifterOper, taskNo, startFloor, LifterLayerType.TWO_CAR_LAYER, startLocal,
                    LifterTaskProcess.GO_TO_START);
            process = LifterTaskProcess.GET_CARGO;
        }

        //取货
        if (process == LifterTaskProcess.GET_CARGO) {
            gotoTarget(lifterOper, taskNo, startFloor, LifterLayerType.TWO_CAR_LAYER, startLocal,
                    LifterTaskProcess.GET_CARGO);
            process = LifterTaskProcess.GET_CARGO_TO_LIFTER;
        }

        //取货完成回提升机内
        if (process == LifterTaskProcess.GET_CARGO_TO_LIFTER) {
            gotoTarget(lifterOper, taskNo, startFloor, LifterLayerType.TWO_CAR_LAYER, LifterLocationType.INSIDE,
                    LifterTaskProcess.GET_CARGO_TO_LIFTER);
            process = LifterTaskProcess.GO_TO_TARGET_FLOOR;
        }

        //前往终点层
        if (process == LifterTaskProcess.GO_TO_TARGET_FLOOR) {
            gotoTarget(lifterOper, taskNo, endFloor, LifterLayerType.TWO_CAR_LAYER, LifterLocationType.INSIDE,
                    LifterTaskProcess.GO_TO_TARGET_FLOOR);
            process = LifterTaskProcess.GO_TO_END;
        }

        //前往终点
        if (process == LifterTaskProcess.GO_TO_END) {
            gotoTarget(lifterOper, taskNo, endFloor, LifterLayerType.TWO_CAR_LAYER, endLocal,
                    LifterTaskProcess.GO_TO_END);
            process = LifterTaskProcess.PUT_CARGO;
        }
        //放货
        if (process == LifterTaskProcess.PUT_CARGO) {
            gotoTarget(lifterOper, taskNo, endFloor, LifterLayerType.TWO_CAR_LAYER, endLocal,
                    LifterTaskProcess.PUT_CARGO);
            process = LifterTaskProcess.BACK_LIFTER;
        }
        //回提升机内
        if (process == LifterTaskProcess.BACK_LIFTER) {
            gotoTarget(lifterOper, taskNo, endFloor, LifterLayerType.TWO_CAR_LAYER, LifterLocationType.INSIDE,
                    LifterTaskProcess.BACK_LIFTER);
            process = LifterTaskProcess.END;
        }
        taskManage.sendTask(taskNo);
    }

    /**
     * 检测两向车托盘状态
     * @param lifterOper
     * @param process
     * @param startFloor
     * @param startLocal
     * @param endFloor
     * @param endLocal
     */
    private void checkPallet(ForkLifterOper lifterOper, LifterTaskProcess process, int startFloor,
                             LifterLocationType startLocal, int endFloor, LifterLocationType endLocal) {
        if (process == null || process == LifterTaskProcess.INIT || process == LifterTaskProcess.GO_TO_START) {
            //前往起点
            if (!lifterOper.isTwoCarDownOk()) {
                throw new RuntimeException(lifterOper.getDeviceName() + "托盘状态未下降不能去起点取货:" + startFloor + "层,"
                        + startLocal);
            }
        } else if (process == LifterTaskProcess.GO_TO_END) {
            //前往终点
            if (!lifterOper.isTwoCarUpOk()) {
                throw new RuntimeException(lifterOper.getDeviceName() + "托盘状态未顶升不能去终点放货:" + endFloor + "层,"
                        + endLocal);
            }
        } else if (process == LifterTaskProcess.BACK_LIFTER) {
            //回提升机内
            if (!lifterOper.isTwoCarDownOk()) {
                throw new RuntimeException(lifterOper.getDeviceName() + "托盘状态未下降不能回提升机内");
            }
        }
    }

    /**
     * 解析提升机位置
     * @param location
     * @return
     */
    public LifterLocationType analyzeLocation(int location) {
        Location local = Location.parseLocationCode(location);
        return analyzeLocation(local);
    }

    /**
     * 解析提升机位置
     * @param location
     * @return
     */
    public LifterLocationType analyzeLocation(Location location) {
        switch (location) {
            case LEFT:
                return LifterLocationType.LEFT;
            case RIGHT:
                return LifterLocationType.RIGHT;
            case INSIDE:
                return LifterLocationType.INSIDE;
            default:
                throw new RuntimeException("提升机位置错误:" + location);
        }
    }

    /**
     * 前往目的点
     * @param lifterOper
     * @param taskId
     * @param layer
     * @param layerType
     * @param locationType
     * @param process
     */
    public void gotoTarget(ForkLifterOper lifterOper, int taskId, int layer, LifterLayerType layerType,
                           LifterLocationType locationType, LifterTaskProcess process) {
        LifterTaskManage taskManage = LifterTaskManage.getInstance(lifterOper);
        if (process == LifterTaskProcess.GET_CARGO) {
            taskManage.sendPalletTask(taskId, PalletStatus.UP, process);
        } else if (process == LifterTaskProcess.PUT_CARGO) {
            taskManage.sendPalletTask(taskId, PalletStatus.DOWN, process);
        } else {
            taskManage.gotoTargetLocation(taskId, new LifterLocationInfo(layer, layerType, locationType), process);
        }
    }

    /**
     * 提升机是否就绪
     * @param lifterOper
     */
    public void checkReady(ForkLifterOper lifterOper) {
        if (lifterOper.isRuning()) {
            throw new RuntimeException("提升机运行中，不能操作提升机");
        }

        if (lifterOper.isTasking()) {
            throw new RuntimeException("提升机任务执行中，不能操作提升机");
        }

        if (!lifterOper.isArrived()) {
            throw new RuntimeException("提升机或两向车未到位，不能操作提升机");
        }

        if (!lifterOper.isReady()) {
            throw new RuntimeException("提升机当前未就绪");
        }
    }

    /**
     * 托盘升
     * @param lifterOper
     * @param taskId
     * @throws IOException
     */
    public void palletUpManual(ForkLifterOper lifterOper, int taskId) throws IOException {
        LifterTaskManage taskManage = LifterTaskManage.getInstance(lifterOper);
        taskManage.sendPalletTaskOnly(taskId, PalletStatus.UP, LifterTaskProcess.GET_CARGO);
        taskManage.sendTask(taskId);
        taskManage.allTaskRun(taskId);
    }

    /**
     * 托盘降
     * @param lifterOper
     * @param taskId
     * @throws IOException
     */
    public void palletDownManual(ForkLifterOper lifterOper, int taskId) throws IOException {
        LifterTaskManage taskManage = LifterTaskManage.getInstance(lifterOper);
        taskManage.sendPalletTaskOnly(taskId, PalletStatus.DOWN, LifterTaskProcess.PUT_CARGO);
        taskManage.sendTask(taskId);
        taskManage.allTaskRun(taskId);
    }

    /**
     * 设置提升机层位移量
     * @param layer
     * @param isFourLayer
     * @throws IOException
     */
    public void setLifterDis(int layer, boolean isFourLayer, ForkLifterOper lifterOper) throws IOException {
        layer = LifterMap.combineLayer(layer, isFourLayer);
        int lifterDis = lifterOper.getLifterDis();
        lifterOper.setLifterDis(layer, lifterOper.getLifterDis());
        if (lifterOper.getLifterLayerMap().get(layer) == null) {
            lifterInfoFunc.saveLifterInfo(new LifterMap(layer, lifterDis), lifterOper.getSeries());
        } else {
            lifterInfoFunc.updateLifterInfo(new LifterMap(layer, lifterDis), lifterOper.getSeries());
        }
        PlcInit.refreshLifterInfo(lifterOper);
    }

    /**
     * 设置两向车位移量
     * @param layer
     * @param locationType
     * @param lifterOper
     * @throws IOException
     */
    public void setCarDis(int layer, LifterLocationType locationType, ForkLifterOper lifterOper) throws IOException {
        lifterOper.setCarDis(layer, locationType);
        Location location = null;
        switch (locationType) {
            case INSIDE:
                location = Location.INSIDE;
                break;
            case LEFT:
                location = Location.LEFT;
                break;
            case RIGHT:
                location = Location.RIGHT;
                break;
            default:
                throw new RuntimeException("错误的提升机位置:" + locationType);
        }
        Coord coord = Plc.lifterLocationMap.get(lifterOper.getPlcId()).get(location);
        coord.setZ(layer);
        if (lifterOper.getCarLocationMap().get(coord) == null) {
            for (CarMap value : lifterOper.getCarLocationMap().values()) {
                if (value.groundCode.equals(String.valueOf(lifterOper.getTwoCarGroundCode()))) {
                    throw new RuntimeException("当前地码已存在：" + value);
                }
            }
            lifterInfoFunc.saveCarInfo(
                    new CarMap(coord, locationType, String.valueOf(lifterOper.getTwoCarGroundCode()),
                            lifterOper.getTwoCarDis()),
                    lifterOper.getSeries());
        } else {
            lifterInfoFunc.updateCarInfo(
                    new CarMap(coord, locationType, String.valueOf(lifterOper.getTwoCarGroundCode()),
                            lifterOper.getTwoCarDis()),
                    lifterOper.getSeries());
        }
        PlcInit.refreshLifterInfo(lifterOper);
    }

    /**
     * 设置托盘位移量
     * @param palletStatus
     * @param lifterOper
     * @throws IOException
     */
    public void setCarPalletDis(PalletStatus palletStatus, ForkLifterOper lifterOper) throws IOException {
        lifterOper.setCarPalletDis(palletStatus);
        if (lifterOper.getPalletStatusMap().get(palletStatus) == null) {
            lifterInfoFunc.savePalletInfo(new PalletMap(palletStatus, lifterOper.getTwoCarPalletDis()),
                    lifterOper.getSeries());
        } else {
            lifterInfoFunc.updatePalletInfo(new PalletMap(palletStatus, lifterOper.getTwoCarPalletDis()),
                    lifterOper.getSeries());
        }
        PlcInit.refreshLifterInfo(lifterOper);
    }

    public void setHoistFinalTaskNoClear(ForkLifterOper lifterOper) throws IOException {
        LifterTaskManage.getInstance(lifterOper).init();
        lifterOper.setHoistFinalTaskNoClear();
    }

    @Override
    public boolean isPalletExisted(LifterOper lifterOper, Integer endLayer, Location endLocation) {
        return isLocationHasCargo(lifterOper, endLayer, endLocation);
    }
}
